home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Alles Voor Internet / Tout Pour Internet
/
alles voor internet.iso
/
MacInternet™
/
Archive-tools
/
ql read Folder
/
QLTOOLS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-14
|
11KB
|
516 lines
/*
QLTOOLS
Read a QL floppy disk
(c)1992 by Giuseppe Zanetti
Giuseppe Zanetti
via Vergani, 11 - 35031 Abano Terme (Pdaova) ITALY
e-mail: beppe@sabrina.dei.unipd.it
Think C adaption Roberto Avanzi
via Luigi Balzan 12 - 45100 Rovigo ITALY
e-mail: gandalf@sabrina.dei.unipd.it
*/
#define VERSION 1.0 Sep 24 1992
#include <stdio.h>
#ifdef THINK_C
#include "console.h"
#include <string.h>
#else
#include <strings.h>
#endif
/* this line is neccessary since stdio.h in SUN 4.0 do not define it */
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
FILE *f;
static unsigned char b[512*3];
static unsigned char b0[512*3];
static unsigned char ltp[18];
static unsigned char ptl[18];
static unsigned long int bleod;
static unsigned char byeod;
static unsigned char *pdir;
static unsigned int convtable[1440];
static int gsides,gtracks,gsectors,goffset;
long int lwrd(p)
unsigned char *p;
{
return ( (long int) ( *(p+3) + *(p+2)*0x100 + *(p+1)*0x10000 + *(p)*0x1000000 ) );
}
void cat_file(fnum)
long int fnum;
{
long int flen,file,blk;
int i,s,c,start,end;
char buffer[512*3];
unsigned char *base;
flen=lwrd(pdir+fnum*64); /* with the header */
/* printf("cat file #%i len=%ld blocks=%ld + %d\n\n",fnum,flen,flen/(512*3),flen % (512*3)); */
for (s=0;s<=flen/(512*3);s++)
{
for (i=0;i<(wrd(b0+28)*wrd(b0+30))/wrd(b0+32);i++)
{
base=b0+0x4C+20+i*3;
file=(int) (*(base) * 0x10) + (int) ((*(base+1) >> 4) & 0x0F) ;
blk= (*(base+1) & 0x0F)*0x100 + *(base+2);
/* printf("%ld/%ld\n",file,blk); */
if (file == fnum)
{
if (blk == s)
{
read_block(buffer,i);
start=0; if (s==0) start=64;
end=512*3; if (s==(flen/(512*3))) end=flen % (512*3);
for(c=start;c<end;c++) printf("%c",*(buffer+c));
}
}
}
}
}
void usage(error)
char *error;
{
fprintf(stderr,"error %s\n\n",error);
fprintf(stderr,"Usage: qltools diskimage -[options] [filename]\n\n");
fprintf(stderr,"options:\n\n");
fprintf(stderr,"-d list directory\n");
fprintf(stderr,"-i list info\n");
fprintf(stderr,"-m list disk map\n");
fprintf(stderr,"-c list conversion table of sectors\n");
fprintf(stderr,"-nFN output file number NF in the directory listing\n\n");
fprintf(stderr,"diskimage is either a file with the image of a QL format disk\n");
fprintf(stderr,"or a unix device with a ql disk inserted in it (/dev/fd...)\n\n");
fprintf(stderr,"Giuseppe Zanetti\n");
fprintf(stderr,"via Vergani, 11 - 35031 Abano Terme (Pdaova) ITALY\n");
fprintf(stderr,"e-mail: beppe@sabrina.dei.unipd.it\n");
exit(1);
}
void print_info()
{
int i;
printf("Disk Id : ");
for (i=0;i<4;i++)
{
printf("%c",b0[i]);
}
printf("\n");
printf("Disk Label : ");
for (i=0;i<10;i++)
{
printf("%c",b0[4+i]);
}
printf("\n");
printf("Sectors per track: %i\n",gsectors);
printf("sectors per cyl. : %i\n",wrd(b0+28));
printf("number of cylind.: %i\n",gtracks);
printf("allocation block : %i\n",wrd(b0+32));
printf("sector offset/cyl: %i\n",goffset);
printf("free sectors : %i\n",wrd(b0+20));
printf("good sectors : %i\n",wrd(b0+22));
printf("total sectors : %i\n",wrd(b0+24));
printf("directory is : %i sectors and %u bytes\n",bleod,byeod);
printf("\nlogical-to-physical sector mapping table:\n\n");
for (i=0;i<18;i++) printf("%u ",ltp[i]);
printf("\n");
printf("\nphysical-to-logical sector mapping table:\n\n");
for (i=0;i<18;i++) printf("%u ",ptl[i]);
printf("\n");
}
void print_dir()
{
int d,i;
char c;
for (i=0;i<10;i++)
{
printf("%c",b0[4+i]);
}
printf("\n");
printf("%i/%i sectors.\n\n",wrd(b0+20),wrd(b0+22));
for (d=64;d <512*bleod+byeod;d+=64)
{
printf("%3i : ",d/64);
for (i=0;i<wrd(pdir+d+14);i++)
{
c=*(pdir+d+16+i);
printf("%c",c);
}
for(i=0;i<38-wrd(pdir+d+14);i++) printf(" ");
switch(*(pdir+d+5))
{
case 0: printf(" "); break;
case 1: printf("executable"); break;
case 2: printf("relocable "); break;
default:printf("bad type "); break;
}
printf(" %ld\n",lwrd(pdir+d) - 64);
}
}
void make_convtable(verbose)
int verbose;
{
int i,si,tr,se,ls,ps,uxs;
if (verbose)
{
printf("\nCONVERSION TABLE\n\n");
printf("logic\ttrack\tside\tsector\tunix_dev\n\n");
}
for(i=0;i<gtracks*gsectors*gsides;i++)
{
tr=i / (gsectors*gsides);
ls=i % (gsectors*gsides);
ps = ltp[ls];
si=(ps & 0x80) != 0;
ps &= 0x7F;
ps += goffset*tr;
se = ps % gsectors;
uxs = tr*gsectors*gsides+gsectors*si+se;
convtable[i] = uxs;
if (verbose)
{
printf("%i\t%i\t%i\t%i\t%i\n",i,tr,si,se,uxs);
}
}
}
int wrd(wp)
char *wp;
{
int r;
r=*(wp)*256 + *(wp+1);
return r;
}
int read_block0()
{
int i;
fseek(f,0,SEEK_SET);
fread(b0,512,1,f);
fseek(f,512*3,SEEK_SET);
fread(b0+512,512,1,f);
fseek(f,512*6,SEEK_SET);
fread(b0+1024,512,1,f);
/* read ptl and ptl tables */
for (i=0;i<18;i++)
{
ltp[i] = *(b0+40+i);
ptl[i] = *(b0+58+i);
}
return(0);
}
int read_block(p,num)
char *p;
int num;
{
int i;
int r=0;
for(i=0;i<3;i++)
{
fseek(f,(512*convtable[num*3+i]),SEEK_SET);
r += fread(p+512*i,512,1,f);
}
return(r);
}
long int match_file(fname)
char *fname;
{
int d,i,match,len;
long int r=0L;
char c;
len=strlen(fname);
for (d=64;d <512*bleod+byeod;d+=64)
{
match=1;
if (wrd(pdir+d+14) == len)
{
for (i=0;i<len;i++)
{
c=*(pdir+d+16+i);
if (c != fname[i]) match=0;
}
if (match)
{
r=d/64;
break;
}
}
}
return(r);
}
main(argc,argv)
int argc;
char * argv[];
{
int i;
unsigned long int finfofile, finfoblk;
unsigned char *base;
int argdir,arginfo,argfnum,argmap,argconv;
char argfname[255];
#ifdef THINK_C
argc=ccommand(&argv);
#endif
argdir=arginfo=argfnum=argmap=argconv=0;
strcpy(argfname,"");
if (argc < 2)
{
usage("too few parameters");
}
for(i=2;i<argc;i++)
{
if (argv[i][0] == '-')
{
switch(argv[i][1])
{
case 'd': argdir=1; break;
case 'i': arginfo=1; break;
case 'm': argmap=1; break;
case 'c': argconv=1; break;
case 'n': argfnum=atol(argv[i]+2); break;
default: usage("bad option"); break;
}
}
else
{
strcpy(argfname,argv[i]);
}
}
f=fopen(argv[1],"rb");
if (f==NULL)
{
usage("bad image file or device");
}
read_block0();
gsides=2;
gtracks=wrd(b0+30);
gsectors=wrd(b0+26);
goffset=wrd(b0+38);
bleod=wrd(b0+34);
byeod=wrd(b0+36);
pdir=(unsigned char *) malloc(512*(bleod+1));
make_convtable(argconv);
/* read the directory map */
if (argmap)
{
printf("\nblock\tfile\tpos\n\n");
}
for (i=0;i<(wrd(b0+28)*wrd(b0+30))/wrd(b0+32);i++)
{
base=b0+0x4C+20+i*3;
finfofile= (unsigned long int) (*(base) * 0x10) + (unsigned long int) ((*(base+1) >> 4) & 0x0F) ;
finfoblk= (*(base+1) & 0x0F)*0x100 + *(base+2);
if (finfofile == 0x00)
{
read_block(pdir+512*3*finfoblk,i);
}
if (argmap)
{
printf("%d\t%ld\t%ld\t",i,finfofile,finfoblk);
switch(finfofile)
{
case 0x000: printf("directory %i\n",finfoblk); break;
case 0xF80: printf("map\n"); break;
case 0xFDF: printf("unused\n"); break;
case 0xFEF: printf("bad\n"); break;
case 0xFFF: printf("not existent\n"); break;
default: printf("\n"); break;
}
}
}
if (arginfo) print_info();
if (argdir) print_dir();
if (argfnum != 0) cat_file(argfnum);
if (strcmp(argfname,"") != 0)
{
argfnum=match_file(argfname);
if (argfnum == 0)
{
fprintf(stderr,"file not found\n");
exit(2);
}
cat_file(argfnum);
}
fclose(f);
return (0);
}
/*
What exactly do you want to know? I don't know about the
3.2MB format, but I can tell you about 720k. Allocation blocks are 3
sectors long (normally. This can be changed) and the block 0
(consisting of sectors 0, 3 and 6 of side 0 on cylinder 0) contains
the mapping info. The first 96 bytes are used as follows:
OFFSET SIZE VALUE
$00 .L $514C3541
$04 10 bytes disk label
$0E .W random number (created by FORMAT)
$10 .L #writes to this disk
$14 .W #free sectors
$16 .W #good sectors
$18 .W total sectors
$1A .W #sectors per track (9)
$1C .W #sectors per cylinder (18 for DS)
$1E .W number of cylinders (80)
$20 .W size of allocation block (3)
$22 .W block number for end-of-directory
$24 .W byte number of end-of-directory
$26 .W sector offset/cylinder
$28 18 bytes logical-to-physical sector mapping table
$3A 18 bytes physical-to-logical sector mapping table
$4C 20 bytes unused
The rest of the block consists of pairs of 12-bit values (24 bits for
each block on a fully formatted, 80 track, double sided disk) the
first of which contains the file number which that block belongs to,
the seconds holds the position of this block within that file. Some
special file numbers are used for the mapping block itself ($F80),
unused blocks ($FDF), bad blocks ($FEF) and non-existant blocks ($FFF)
and the block-number of unused, bad and non-existant blocks is always
$FFF (but when a file is deleted, only the top byte is set to $FD)
the map is $F80 000 - it consists of one block! The directory
is file number $000, and all other files have numbers corresponding to
their positions in the directory (file $001 is the first, $002 is the
second, etc.)
The "logical-to-physical sector mapping table" contains a byte
for each sector on a cylinder (18) corresponding to the physical
sector number (0 to 8, with the MSB set for sectors on side 1) for
each logical file sector. This table is always "0 3 6 128 131 134 1 4
7 129 132 135 2 5 8 130 133 136" (unless someone has changed it)
meaning sectors 0, 3, 6 of side 0 are used first, then sectors 0, 3, 6
of side 1, then sectors 1, 4, 7 of side 0, etc. _BUT_ the sector
number is offset by an amount depending on the cylinder number (the
numbers above are correct for cylinder 0, but the "sector
offset/track" value is added (mod 9) for each cylinder. This value is
usually 5, so the table values are correct again at cylinder 9)
The "physical-to-logical sector mapping table" contains 9
entries for each side of the disk, containing the logical sector
numbers of the physical sectors on the disk. It is "0 6 12 1 7 13 2 8
14" for side 0 and "3 9 15 4 1 16 5 11 17" for side 1 (that is, for
side 0, phys. sector 0 contains log. sector 0, phys. sector 1 contains
log. sector 6, ...) again, this is affected by the "sector
offset/track".
The directory consists of 64 '0's ($30 bytes, not $00 bytes.
I don't know what they're for) followed by a 64 byte entry for each
file, in the following format:
OFFSET SIZE USE
$00 .L file length
$04 .B unused
$05 .B file type
$06 .L dataspace (for exec'able programs)
$0A .L unused
$0E .W length of file name
$10 36 bytes file name
$34 .L file update date
$38 .L unused. Supposed to be reference date.
$3C .L unused. Supposed to be backup date.
The first 64 bytes in the first block of each file contains a copy of
the directory entry, but most of the information in it is not correct
(the name is OK, though)
Hope that helps.
- Paul
*/